import type { CascadeModel } from "@/types";
import { isArray, isFunction, isNumber, isString } from "@/utils";
import { Cascader as ArcoCascader } from "@arco-design/web-react";
import useFormContext from "@arco-design/web-react/es/Form/hooks/useContext";
import { type ReactNode, useEffect, useState } from "react";

interface CascaderProps {
	value?: string | number | string[] | number[];
	data: CascadeModel[] | ((params: unknown) => Promise<CascadeModel[]>);
	params?: object;
	changeOnSelect?: boolean;
	placeholder?: string;
	labelField?: string;
	valueField?: string;
	multiple?: boolean;
	renderFormat?: (value: any[]) => ReactNode;
	onChange?: (value: string | string[]) => void;
}

export default function Cascader({
	value,
	data,
	params,
	changeOnSelect = false,
	placeholder = "请选择",
	labelField = "text",
	valueField = "value",
	multiple = false,
	renderFormat,
	onChange,
}: CascaderProps) {
	const cascaderValue = isNumber(value)
		? [value.toString()]
		: isString(value)
			? [value]
			: isArray(value)
				? [value.map((v: string | number) => v.toString())]
				: value;
	const { disabled: formDisabled } = useFormContext();

	const [options, setOptions] = useState<CascadeModel[]>([]);
	useEffect(() => {
		function normalizeData(data: CascadeModel[]): CascadeModel[] {
			for (const item of data) {
				if (item.children !== null && item.children !== undefined) {
					if (item.children.length === 0) {
						item.children = undefined;
						continue;
					}
					item.children = normalizeData(item.children);
				}
			}
			return data;
		}
		if (isFunction(data)) {
			data(params).then((res) => {
				setOptions(normalizeData(res));
			});
		} else {
			setOptions(normalizeData(data));
		}
	}, [data, params]);

	return (
		<ArcoCascader
			value={cascaderValue}
			fieldNames={{ label: labelField, value: valueField }}
			changeOnSelect={changeOnSelect}
			options={options}
			placeholder={placeholder}
			mode={multiple ? "multiple" : undefined}
			renderFormat={renderFormat}
			disabled={formDisabled}
			allowClear
			onChange={(value) => onChange?.(value[0])}
		/>
	);
}
